﻿
//Copyright (c) Microsoft
//All rights reserved
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.SqlServer.Dts.Runtime;
using System.Text.RegularExpressions;

namespace PackageConfigs
{
    public partial class frmPropertyEditor : Form
    {
        private bool _isSourceSQLserver = true;

        private string _SQLServerName, _username, _password;

        public frmPropertyEditor()
        {
            InitializeComponent();
            gbFileSystemSource.Top = gbSQLSource.Top;
            SetSource();
        }

        private void btnLoadPackages_Click(object sender, EventArgs e)
        {
            try
            {
                SetBusy(true, "Loading Packages...");
                if (rbSQLServer.Checked)
                {
                    List<PackageRecord> packageRecords = GetPackagesFromSQL(txtPackageFolder.Text.Trim(), txtServerName.Text.Trim(), txtUsername.Text.Trim(), txtPassword.Text);

                    dgvPackages.DataSource = packageRecords;
                    _SQLServerName = txtServerName.Text.Trim();
                    _username = txtUsername.Text.Trim();
                    _password = txtPassword.Text;
                    _isSourceSQLserver = true;
                }
                else        // File source 
                {
                    List<PackageRecord> packageRecords = GetPackagesFromFileSystem(txtPath.Text.Trim());

                    dgvPackages.DataSource = packageRecords;
                    _isSourceSQLserver = false;
                }
                if (dgvProperties.Rows.Count==0)
                    GeneratePropertyCollection();
                SetBusy(false, "");
            }             
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Error: {0}" + Environment.NewLine, ex.Message));
                SetBusy(false, "");
            }
        }

        private List<PackageRecord> GetPackagesFromSQL(string packagesFolder, string serverName, string userName, string password)
        {
            Microsoft.SqlServer.Dts.Runtime.Application app = new Microsoft.SqlServer.Dts.Runtime.Application();
            var packageInfos = app.GetPackageInfos(packagesFolder, serverName, userName, password);

            List<PackageRecord> packageRecords = new List<PackageRecord>(packageInfos.Count);
            foreach (var packageInfo in packageInfos)
            {
                string packagePath = (packageInfo.Folder != "\\" ? packageInfo.Folder : "") + "/" + packageInfo.Name;
                if (packageInfo.Flags == DTSPackageInfoFlags.Folder)
                {
                    if (chkSubfolders.Checked)
                        packageRecords.AddRange(GetPackagesFromSQL(packagePath, serverName, userName, password));
                }
                else
                {
                    Package pkg = app.LoadFromSqlServer(packagePath, serverName, userName, password, null);                    
                    PackageRecord pr = new PackageRecord { IsSelected = true, Path = packagePath, CreationDate = packageInfo.CreationDate };
                    packageRecords.Add(pr);
                }
            }
            return packageRecords;
        }

        private List<PackageRecord> GetPackagesFromFileSystem(string packagesFolder)
        {
            StringBuilder errors = new StringBuilder();

            var packagePaths = System.IO.Directory.GetFiles(packagesFolder, "*.dtsx");

            List<PackageRecord> packageRecords = new List<PackageRecord>(packagePaths.Length);

            Microsoft.SqlServer.Dts.Runtime.Application app = new Microsoft.SqlServer.Dts.Runtime.Application();

            foreach (var packagePath in packagePaths)
            {
                try
                {
                    var packageInfo = app.LoadPackage(packagePath, null);

                    PackageRecord pr = new PackageRecord { IsSelected = true, Path = packagePath, CreationDate = packageInfo.CreationDate };
                    packageRecords.Add(pr);
                }
                catch (Exception ex)
                {
                    errors.AppendFormat("{0} - Error: {1}" + Environment.NewLine, packagePath, ex.Message);
                }
            }
            if (errors.ToString() != "")
                MessageBox.Show("Unable to load some packages: " + Environment.NewLine + Environment.NewLine + errors);

            return packageRecords;
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            if (System.IO.Directory.Exists(txtPath.Text.Trim()))
                dlg.SelectedPath = txtPath.Text.Trim();

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                txtPath.Text = dlg.SelectedPath;
            }
        }

        private void rbFileSystem_CheckedChanged(object sender, EventArgs e)
        {
            SetSource();
        }

        private void rbSQLServer_CheckedChanged(object sender, EventArgs e)
        {
            SetSource();
        }

        private void SetSource()
        {
            if (rbFileSystem.Checked)
            {
                gbFileSystemSource.Visible = true;
                gbSQLSource.Visible = false;
            }
            else
            {
                gbFileSystemSource.Visible = false;
                gbSQLSource.Visible = true;
            }
        }

        private void btnBrowseOutputFolder_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            if (System.IO.Directory.Exists(txtPath.Text.Trim()))
                dlg.SelectedPath = txtOutputFolder.Text.Trim();

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                txtOutputFolder.Text = dlg.SelectedPath;
            }
        }

        private void btnApplyChange_Click(object sender, EventArgs e)
        {
            StringBuilder errors = new StringBuilder();
            SetBusy(true, "Applying Changes...");
            if (dgvPackages.DataSource == null || !(dgvPackages.DataSource is List<PackageRecord>))
            {
                SetBusy(false, "");
                MessageBox.Show("Please load the packages first.", "Package Property Editor");                
                return;
            }

            List<PackageRecord> packageRecords = dgvPackages.DataSource as List<PackageRecord>;
            if (!packageRecords.Exists(x => x.IsSelected))
            {
                SetBusy(false, "");
                MessageBox.Show("No package selected. Please select at least one package.", "Package Property Editor");                
                return;
            }
            string dirPath = txtOutputFolder.Text.Trim();

            if (!System.IO.Directory.Exists(dirPath))
            {
                try
                {
                    System.IO.Directory.CreateDirectory(dirPath);
                }
                catch (Exception ex)
                {
                    SetBusy(false, "");
                    MessageBox.Show("Error in creating the directory '" + dirPath + "' : " + ex.Message, "Package Property Editor");                    
                    return;
                }
            }

            Microsoft.SqlServer.Dts.Runtime.Application app = new Microsoft.SqlServer.Dts.Runtime.Application();

            int engineThreadNewValue = Convert.ToInt16(dgvProperties.Rows[0].Cells[1].Value); 
            int defaultBufferSizeNewValue = Convert.ToInt16(dgvProperties.Rows[1].Cells[1].Value);
            int defaultBufferMaxRowsNewValue = Convert.ToInt16(dgvProperties.Rows[2].Cells[1].Value);
            string bufferTempStoragePathNewValue = Convert.ToString(dgvProperties.Rows[3].Cells[1].Value);
            string BLOBTempStoragePathNewValue = Convert.ToString(dgvProperties.Rows[4].Cells[1].Value);

            
            foreach (var pr in packageRecords)
            {
                if (pr.IsSelected)
                {
                    try
                    {
                        Microsoft.SqlServer.Dts.Runtime.Package pkg = null;
                        string outFileName = "";
                        if (_isSourceSQLserver)
                        {
                            pkg = app.LoadFromSqlServer(pr.Path, _SQLServerName, _username, _password, null);
                            var arr = pr.Path.Split('/');
                            outFileName = arr[arr.Length - 1] + ".dtsx";
                        }
                        else
                        {
                            pkg = app.LoadPackage(pr.Path, null);
                            foreach (var exec in pkg.Executables)
                            {
                                if (exec is Microsoft.SqlServer.Dts.Runtime.TaskHost)
                                {
                                    var taskHost = exec as Microsoft.SqlServer.Dts.Runtime.TaskHost;
                                    if (taskHost.InnerObject is Microsoft.SqlServer.Dts.Pipeline.Wrapper.MainPipe)
                                    {
                                        Microsoft.SqlServer.Dts.Pipeline.Wrapper.MainPipe pipe = taskHost.InnerObject as Microsoft.SqlServer.Dts.Pipeline.Wrapper.MainPipe;
                                        if (engineThreadNewValue!=0)pipe.EngineThreads = engineThreadNewValue;
                                        if (defaultBufferSizeNewValue!=0)pipe.DefaultBufferSize = defaultBufferSizeNewValue*1024*1024;
                                        if (defaultBufferMaxRowsNewValue!=0)pipe.DefaultBufferMaxRows = defaultBufferMaxRowsNewValue;
                                        if (bufferTempStoragePathNewValue != "") pipe.BufferTempStoragePath = bufferTempStoragePathNewValue;
                                        if (BLOBTempStoragePathNewValue != "") pipe.BLOBTempStoragePath = BLOBTempStoragePathNewValue;
                                    }
                                }
                            }
                            outFileName = System.IO.Path.GetFileName(pr.Path);
                        }
                        if (pkg == null)
                            throw new Exception("Unable to load the source package");


                        string outFilePath = System.IO.Path.Combine(dirPath, outFileName);
                        app.SaveToXml(outFilePath, pkg, null);
                    }
                    catch (Exception ex)
                    {
                        SetBusy(false, "");
                        errors.AppendFormat("Error in updating package '{0}' : {1}", pr.Path, ex.Message);                        
                    }
                }
            }
            SetBusy(false, "");
            if (errors.ToString() != "")
                MessageBox.Show("Unable to update some packages: " + Environment.NewLine + Environment.NewLine + errors,"Package Property Editor");
            else
                MessageBox.Show("All packages have been modified successfully.", "Package Property Editor");
        }

        private void btnSelectAllPackages_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (dgvPackages.DataSource == null)
                return;

            var records = dgvPackages.DataSource as List<PackageRecord>;
            foreach (var record in records)
                record.IsSelected = true;

            dgvPackages.Refresh();
        }

        private void btnUnselectPackages_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (dgvPackages.DataSource == null)
                return;

            var records = dgvPackages.DataSource as List<PackageRecord>;
            foreach (var record in records)
                record.IsSelected = false;

            dgvPackages.Refresh();
        }

        //Generate the Property Collection
        private void GeneratePropertyCollection()
        {
            if (dgvPackages.Rows.Count == 0) return;
            String[] row = new String[] { "EngineThreads" };
            dgvProperties.Rows.Add(row);
            String[] row1 = new String[] { "DefaultBufferSize (in MB)" };
            dgvProperties.Rows.Add(row1);
            String[] row2 = new String[] { "DefaultBufferMaxRows" };
            dgvProperties.Rows.Add(row2);
            String[] row3 = new String[] { "BufferTempStoragePath" };
            dgvProperties.Rows.Add(row3);
            String[] row4 = new String[] { "BLOBTempStoragePath" };
            dgvProperties.Rows.Add(row4);
        }

        private void SetBusy(bool busy, string message)
        {
            if (busy)
            {
                pnlMain.Enabled = false;                
                lblBusyMessage.Text = message;
                pnlBusy.Visible = true;
                UseWaitCursor = true;
            }
            else
            {
                pnlBusy.Visible = false;
                pnlMain.Enabled = true;
                UseWaitCursor = false;
            }
        }
    }
}